package com.pe.pgn.clubpgn.dao.impl;

import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.pe.pgn.clubpgn.common.CLPConstantes;
import com.pe.pgn.clubpgn.dao.ProgramaDao;
import com.pe.pgn.clubpgn.dao.hibernate.GenericDaoHibernate;
import com.pe.pgn.clubpgn.domain.ClpbPrograma;
import com.pe.pgn.clubpgn.domain.ClpdUnidadMedida;
import com.pe.pgn.clubpgn.domain.beans.BNProgramaDetalle;
import com.pe.pgn.clubpgn.webapp.util.CalendarUtil;
import com.pe.pgn.clubpgn.webapp.util.ValidationUtil;

/**
 * @author Frank
 * */

@SuppressWarnings("unchecked")
@Repository("programaDao")
public class ProgramaDaoImpl extends GenericDaoHibernate<ClpbPrograma, Long> implements ProgramaDao {

	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	public ProgramaDaoImpl() {
		super(ClpbPrograma.class);
	}

	public List<ClpbPrograma> findListaProgramas() {

		Criteria criteria = DetachedCriteria.forClass(ClpbPrograma.class)
		.getExecutableCriteria(getSessionFactory().getCurrentSession());
		
		criteria.add(Restrictions.eq("stPrograma", Boolean.TRUE));
		criteria.addOrder(Order.desc("id"));
	
		List<ClpbPrograma> lista = criteria.list();
		for (int i = 0;i < lista.size(); i++) {
			
			ClpbPrograma clpbPrograma = lista.get(i);
			Calendar daFechaInicioVigencia = clpbPrograma.getDaFechaInicioVigencia();
			Calendar daFechaFinVigencia = clpbPrograma.getDaFechaFinVigencia();
			
			String desFechaInicioVigencia = CalendarUtil.calendarToString(CLPConstantes.DATE_PATTERN, daFechaInicioVigencia);
			String desFechaFinVigencia = CalendarUtil.calendarToString(CLPConstantes.DATE_PATTERN, daFechaFinVigencia);
			
			clpbPrograma.setDesFechaInicioVigencia(desFechaInicioVigencia);
			clpbPrograma.setDesFechaFinVigencia(desFechaFinVigencia);
			lista.set(i,clpbPrograma);
		}		
		
		return lista;
	}

	public ClpbPrograma getProgramaPorID(Long idPrograma) {

		ClpbPrograma clpbPrograma = get(idPrograma);
		Calendar daFechaInicioVigencia = clpbPrograma.getDaFechaInicioVigencia();
		Calendar daFechaFinVigencia = clpbPrograma.getDaFechaFinVigencia();
		
		Long idUnidadMedida = clpbPrograma.getClpdUnidadMedida().getId();
		boolean indicadorPtos = verificarUnidadMedidaEsParaPtos(
		idUnidadMedida);
		
		clpbPrograma.setStProgramaParaPuntos(indicadorPtos);		
		String desFechaInicioVigencia = CalendarUtil.calendarToString(CLPConstantes.DATE_PATTERN, daFechaInicioVigencia);
		String desFechaFinVigencia = CalendarUtil.calendarToString(CLPConstantes.DATE_PATTERN, daFechaFinVigencia);
		
		clpbPrograma.setDesFechaInicioVigencia(desFechaInicioVigencia);
		clpbPrograma.setDesFechaFinVigencia(desFechaFinVigencia);
		
		clpbPrograma.setProgramas(programasCompatible(idPrograma));
		return clpbPrograma;
	}

	public void eliminarPrograma(Long id) {
	    
		//frk: segun indicaciones la eliminacion es logica
	    String [] deletePrograma = new String[3];
		deletePrograma[0] = "update clpr_periodo_programa set st_periodo_programa = '"+CLPConstantes.ST_FALSO+"' where co_programa="+id;
		deletePrograma[1] = "update clpd_meta set st_meta = '"+CLPConstantes.ST_FALSO+"' where clpb_programa="+id;
		deletePrograma[2] = "update clpb_programa set st_programa = '"+CLPConstantes.ST_FALSO+"' where id=" + id;
		
		jdbcTemplate.batchUpdate(deletePrograma);
	}
	
	public List<BNProgramaDetalle> programasCompatible(Long idPrograma){
		
		StringBuffer query = new StringBuffer();		
		query.append("select pro.id as id , pro.de_programa as descripcion, 'Y' as stNoCompatible ");
		query.append(" from clpb_programa pro ");
		query.append(" LEFT OUTER JOIN clpr_no_compatibilidad comp ON (pro.id= comp.co_programa ");
		query.append(" and pro.id= comp.co_programa_no_compatible) ");
		query.append(" where pro.id<>"+idPrograma);
		query.append(" and pro.st_programa='Y' "); 
		query.append(" and pro.id in ");
		query.append(" (select co_programa_no_compatible from clpr_no_compatibilidad where co_programa="+idPrograma).append(")");
		query.append(" union ");
		query.append(" select pro.id as id , pro.de_programa as descripcion, 'N' as stNoCompatible ");
		query.append(" from clpb_programa pro ");
		query.append(" LEFT OUTER JOIN clpr_no_compatibilidad comp ON (pro.id= comp.co_programa ");
		query.append(" and pro.id= comp.co_programa_no_compatible) ");
		query.append(" where  pro.id<>"+idPrograma);
		query.append(" and pro.st_programa='Y' ");
		query.append(" and pro.id  not in ");
		query.append(" (select co_programa_no_compatible from clpr_no_compatibilidad where co_programa="+idPrograma).append(")");
		
		return findListOfBeans(query.toString(), null, BNProgramaDetalle.class);
	}

	public List<ClpdUnidadMedida> findUnidadMedidas() {
		
		Criteria criteria = DetachedCriteria.forClass(ClpdUnidadMedida.class)
		.getExecutableCriteria(getSessionFactory().getCurrentSession());
		
		criteria.add(Restrictions.eq("stUnidadMedida", Boolean.TRUE));
		criteria.addOrder(Order.desc("id"));
	
		List<ClpdUnidadMedida> lista = criteria.list();
		return lista;
	}

	public Map saveOrUpdatePrograma(ClpbPrograma clpbPrograma) {

		Map mapMsg = new HashMap();
		Long idPrograma = clpbPrograma.getId();		
		List<BNProgramaDetalle> listaNoCompatible = clpbPrograma.getProgramas();
		Long idUnidadMedida = clpbPrograma.getClpdUnidadMedida().getId();
		
		boolean esValido = validaSoloExistaUnProgramaParaPtos(idPrograma,
		idUnidadMedida);
		
		if(!esValido){			
			mapMsg.put(CLPConstantes.MSG, CLPConstantes.ERROR);
			mapMsg.put("detalle", "No se proceso, ya existe un programa que acumula puntos.");			
			return mapMsg;
		}		
		
		boolean indicadorPtos = verificarUnidadMedidaEsParaPtos(
		idUnidadMedida);
		
		if(indicadorPtos){
			clpbPrograma.setStAcumPtos(true);
		}else{
			clpbPrograma.setStAcumPtos(false);
		}
		
		if(idPrograma == null){
			
			clpbPrograma.setStPrograma(true);
			clpbPrograma.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
			clpbPrograma.setDaFechaCreacion(Calendar.getInstance());
		}else{
			
			clpbPrograma.setStPrograma(true);
			clpbPrograma.setCoUsuarioModificador(getUsuarioLogueado().getUsername());
			clpbPrograma.setDaFechaModificacion(Calendar.getInstance());
		}
		
		getHibernateTemplate().saveOrUpdate(clpbPrograma);
		getHibernateTemplate().flush();	
		
		if(idPrograma == null){
			
			for (BNProgramaDetalle bnDetalle : listaNoCompatible) {
				if(bnDetalle.isChkNoCompatible()){
					StringBuffer  sql=new StringBuffer();
					sql.append(" insert into clpr_no_compatibilidad ");
					sql.append(" (id, co_programa, co_programa_no_compatible,st_nocompatibilidad)");
					sql.append(" values(SEQ_NO_COMPATIBLE.NEXTVAL, ");
					sql.append(clpbPrograma.getId());
					sql.append(", "+bnDetalle.getId());
					sql.append(",'Y'"+")");
					jdbcTemplate.execute(sql.toString());
					
					StringBuffer  sqlQuery=new StringBuffer();
					sqlQuery.append(" insert into clpr_no_compatibilidad ");
					sqlQuery.append(" (id, co_programa, co_programa_no_compatible,st_nocompatibilidad)");
					sqlQuery.append(" values(SEQ_NO_COMPATIBLE.NEXTVAL, ");
					sqlQuery.append(bnDetalle.getId());
					sqlQuery.append(", "+clpbPrograma.getId());
					sqlQuery.append(",'Y'"+")");
					jdbcTemplate.execute(sqlQuery.toString());
				}
			}
		}else{
			
			StringBuffer sqlQuery = new StringBuffer();			
			for (BNProgramaDetalle bnDetalle : listaNoCompatible) {
					
					sqlQuery = new StringBuffer();
					sqlQuery.append(" select * from clpr_no_compatibilidad where ");
					sqlQuery.append(" co_programa=").append(clpbPrograma.getId());
					sqlQuery.append(" and co_programa_no_compatible = ").append(bnDetalle.getId());
					List existe = jdbcTemplate.queryForList(sqlQuery.toString());
				
				if(existe.isEmpty()){
					if(bnDetalle.isChkNoCompatible()){
						sqlQuery = new StringBuffer();
						sqlQuery.append(" insert into clpr_no_compatibilidad ");
						sqlQuery.append(" (id, co_programa, co_programa_no_compatible,st_nocompatibilidad)");
						sqlQuery.append(" values(SEQ_NO_COMPATIBLE.NEXTVAL, ");
						sqlQuery.append(clpbPrograma.getId());
						sqlQuery.append(", "+bnDetalle.getId());
						sqlQuery.append(", 'Y'"+")");
						jdbcTemplate.execute(sqlQuery.toString());	
						
						sqlQuery = new StringBuffer();
						sqlQuery.append(" insert into clpr_no_compatibilidad ");
						sqlQuery.append(" (id, co_programa, co_programa_no_compatible,st_nocompatibilidad)");
						sqlQuery.append(" values(SEQ_NO_COMPATIBLE.NEXTVAL, ");
						sqlQuery.append(bnDetalle.getId());
						sqlQuery.append(", "+clpbPrograma.getId());
						sqlQuery.append(", 'Y'"+")");
						jdbcTemplate.execute(sqlQuery.toString());	
						
					}
				}else{
					if(!bnDetalle.isChkNoCompatible()){
						
						sqlQuery = new StringBuffer();
						sqlQuery.append("delete from clpr_no_compatibilidad  ");
						sqlQuery.append("where co_programa=").append(clpbPrograma.getId());
						sqlQuery.append("and co_programa_no_compatible=").append(bnDetalle.getId());
						jdbcTemplate.execute(sqlQuery.toString());
						
						sqlQuery = new StringBuffer();
						sqlQuery.append("delete from clpr_no_compatibilidad  ");
						sqlQuery.append("where co_programa=").append(bnDetalle.getId());
						sqlQuery.append("and co_programa_no_compatible=").append(clpbPrograma.getId());
						jdbcTemplate.execute(sqlQuery.toString());
					}
				}
			}
		}
		
		mapMsg.put(CLPConstantes.MSG, CLPConstantes.SUCCESS);
		return mapMsg;
	}

	private boolean validaSoloExistaUnProgramaParaPtos(Long idPrograma,
			Long idUnidadMedida) {

		//verificando cuantos programas existen con relacion a la acumulacion de puntos
		StringBuffer query = new StringBuffer();
		query.append(" select ");
		query.append(" count(pg.id) ");
		query.append(" from clpb_programa pg ");
		query.append(" join clpd_unidad_medida und on pg.co_unidad_medida = und.id ");
		query.append(" where pg.st_programa = '").append(CLPConstantes.ST_VERDADERO).append("'");
		query.append(" and und.st_unidad_medida = '").append(CLPConstantes.ST_VERDADERO).append("'");
		query.append(" and und.st_indicador_puntos = '").append(CLPConstantes.ST_VERDADERO).append("'");
		
		if(idPrograma != null)
		query.append(" and pg.id != ").append(idPrograma);		
		int conteo = jdbcTemplate.queryForInt(query.toString());
		
		//si existen programas que acumulan puntos
		if(conteo > 0){
			
			boolean indicadorPtos = verificarUnidadMedidaEsParaPtos(
			idUnidadMedida);
			
			if(indicadorPtos){
				return false;
			}			
		}
		
		return true;
	}

	private boolean verificarUnidadMedidaEsParaPtos(Long idUnidadMedida) {

		StringBuffer query = new StringBuffer();
		query.append(" select ");
		query.append(" st_indicador_puntos ");
		query.append(" from clpd_unidad_medida ");
		query.append(" where id = ").append(idUnidadMedida);
		
		List list = jdbcTemplate.queryForList(query.toString());
		Map map = (HashMap)list.get(0);
		
		if(map.get("st_indicador_puntos").toString().equals(CLPConstantes.ST_VERDADERO)){
			return true;
		}
		
		return false;
	}

	/**
	 * frk: el metodo devuelve true si tiene dependencias
	 * */
	
	@SuppressWarnings("rawtypes")
	public boolean verificarDependencias(Long id) {

		String noCompatibilidad ="select * from clpr_no_compatibilidad where co_programa = "+id+
		" and st_nocompatibilidad  = '"+CLPConstantes.ST_VERDADERO+"'";
		List listaNoCompatibilidad = jdbcTemplate.queryForList(noCompatibilidad);
		
		if(!listaNoCompatibilidad.isEmpty())
			return true;
		
		String periodoLiquidacion="select * from clpr_periodo_liquidacion where co_programa="+id+
		" and st_periodo_liquidacion = '"+CLPConstantes.ST_VERDADERO+"'";
		List listaPeriodoLiquidacion = jdbcTemplate.queryForList(periodoLiquidacion);
		
		if(!listaPeriodoLiquidacion.isEmpty())
			return true;
		
		String clientePrograma ="select * from clpr_cliente_programa where clpb_programa="+id+
		" and st_cliente_programa = '"+CLPConstantes.ST_VERDADERO+"'";
		List listaClientePrograma = jdbcTemplate.queryForList(clientePrograma);
		
		if(!listaClientePrograma.isEmpty())
			return true;
		
		return false;
	}

	public String validateProgramasCompatibles(ClpbPrograma clpbPrograma) {

		Long idPrograma = clpbPrograma.getId();
		StringBuffer sqlQuery = new StringBuffer();
		
		List<BNProgramaDetalle> listaNoCompatible = clpbPrograma.getProgramas();
		for (BNProgramaDetalle bnDetalle : listaNoCompatible) {
			
			if(bnDetalle.isChkNoCompatible()){
				
				sqlQuery = new StringBuffer();
				sqlQuery.append(" select ");
				sqlQuery.append("	count(*) ");
				sqlQuery.append(" from clpr_cliente_programa ");
				sqlQuery.append(" where clpb_programa = ").append(bnDetalle.getId());
				sqlQuery.append(" 	and clpb_cliente_persona in (");
				sqlQuery.append(" select distinct ");
				sqlQuery.append("	clpb_cliente_persona ");
				sqlQuery.append(" from clpr_cliente_programa ");
				sqlQuery.append(" where clpb_programa = ").append(idPrograma);					
				
				sqlQuery.append(")");
				int count = jdbcTemplate.queryForInt(sqlQuery.toString());
				
				if(count > 0){
					return bnDetalle.getDescripcion();
				}
			}
		}		
		return null;
	}
}
